package com.wn.advice;

import com.wn.annotion.MyRedis;
import com.wn.mapper.UserMapper;
import com.wn.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @author yellow Docter
 * @date 2023 -06-19
 * @desc
 *
 * 增强的类
 *   切面类
 */
@Slf4j
@Aspect
@Component
public class MyAdviceAnnotation {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * @Around   环绕通知
     *           有参数、pjp 连接点
     *  value = "execution(* com.wn.service.impl.UserServiceImpl.*(..))" 切点表达式
     *  对方法进行增强
     *
     *
     *  具体的业务逻辑实现:
     *  1、拿到所有的连接点
     *  2、通过反射拿到 具体的方法 上面是否有指定的 注解
     *  3、拿到 key (redis 的key )
     *
     *  实现 增强功能
     *  1、实现 缓存
     *     1、查询db
     *     2、存储到redis
     *
     * @return
     */
    @Around(value = "execution(* com.wn.service.impl.UserServiceImpl.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {

        log.info("around 注解解析中执行....");
        //方法签名接口
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();

        //拿到连接点的方法对象
        Method method = methodSignature.getMethod();
        log.info("around 注解解析方法的名称:....{}",method.getName());
        //反射进行判断、 方法是否有这个注解
        if (method.isAnnotationPresent(MyRedis.class)){

            //拿到注解
            MyRedis myRedis = method.getAnnotation(MyRedis.class);
            //解析注解
            String redisKey = myRedis.value();
            System.out.println("redisKey = " + redisKey);

            //查询redis
            Object o = redisTemplate.opsForValue().get(redisKey);

            //没有数据 查询 db
            if (ObjectUtils.isEmpty(o)){
                //查询数据库
                List<User> users = userMapper.selectList(null);
                //存储到 redis中
                redisTemplate.opsForValue().set(redisKey,users);

                return users;
            }
            log.info("从aop缓存中获取的 数据");
            return o;
        }
        return pjp.proceed();
    }
}
